home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP10.ZIP / CHAP10 / SCHMOO / DOCUMENT.CPP < prev    next >
C/C++ Source or Header  |  1993-06-23  |  31KB  |  1,340 lines

  1. /*
  2.  * DOCUMENT.CPP
  3.  *
  4.  * Implementation of the CSchmooDoc derivation of CDocument as
  5.  * well as an implementation of CPolylineAdviseSink.
  6.  *
  7.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Software Design Engineer
  10.  * Microsoft Systems Developer Relations
  11.  *
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15.  
  16.  
  17. #include "schmoo.h"
  18.  
  19.  
  20.  
  21. /*
  22.  * CSchmooDoc::CSchmooDoc
  23.  * CSchmooDoc::~CSchmooDoc
  24.  *
  25.  * Constructor Parameters:
  26.  *  hInst           HINSTANCE of the application.
  27.  */
  28.  
  29. CSchmooDoc::CSchmooDoc(HINSTANCE hInst)
  30.     : CDocument(hInst)
  31.     {
  32.     m_pPL=NULL;
  33.     m_pPLAdv=NULL;
  34.     m_uPrevSize=SIZE_RESTORED;
  35.  
  36.     m_pDropTarget=NULL;
  37.     m_fDragSource=FALSE;
  38.  
  39.     //CHAPTER10MOD
  40.     m_cfEmbedSource=RegisterClipboardFormat(CF_EMBEDSOURCE);
  41.     m_cfObjectDescriptor=RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
  42.  
  43.     m_pFigure=NULL;
  44.     //End CHAPTER10MOD
  45.     return;
  46.     }
  47.  
  48.  
  49. CSchmooDoc::~CSchmooDoc(void)
  50.     {
  51.     //CHAPTER10MOD
  52.     //Make sure the object is saved, the disconnect entirerly
  53.     m_pFigure->SendAdvise(OBJECTCODE_SAVEOBJECT);
  54.     m_pFigure->SendAdvise(OBJECTCODE_HIDEWINDOW);
  55.     m_pFigure->SendAdvise(OBJECTCODE_CLOSED);
  56.     CoDisconnectObject((LPUNKNOWN)m_pFigure, 0L);
  57.  
  58.     if (NULL!=m_pFigure)
  59.         m_pFigure->Release();   //So it can start shutdown if necessary.
  60.     //End CHAPTER10MOD
  61.  
  62.     //Clean up the allocations we did in FInit
  63.     if (NULL!=m_pDropTarget)
  64.         {
  65.         RevokeDragDrop(m_hWnd);
  66.  
  67.         //This lets OLE forget about the object.
  68.         CoLockObjectExternal((LPUNKNOWN)m_pDropTarget, FALSE, TRUE);
  69.  
  70.         m_pDropTarget->Release();
  71.         }
  72.  
  73.     if (NULL!=m_pPL)
  74.         delete m_pPL;
  75.  
  76.     if (NULL!=m_pPLAdv)
  77.         delete m_pPLAdv;
  78.  
  79.     return;
  80.     }
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87. /*
  88.  * CSchmooDoc::FInit
  89.  *
  90.  * Purpose:
  91.  *  Initializes an already created document window.  The client actually
  92.  *  creates the window for us, then passes that here for further
  93.  *  initialization.
  94.  *
  95.  * Parameters:
  96.  *  pDI             LPDOCUMENTINIT containing initialization parameters.
  97.  *
  98.  * Return Value:
  99.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  100.  */
  101.  
  102. BOOL CSchmooDoc::FInit(LPDOCUMENTINIT pDI)
  103.     {
  104.     RECT        rc;
  105.  
  106.     //Change the stringtable range to our customization.
  107.     pDI->idsMin=IDS_DOCUMENTMIN;
  108.     pDI->idsMax=IDS_DOCUMENTMAX;
  109.  
  110.     //Do default initialization
  111.     if (!CDocument::FInit(pDI))
  112.         return FALSE;
  113.  
  114.     //Add the Polyline stuff we need.
  115.     m_pPLAdv=new CPolylineAdviseSink((LPVOID)this);
  116.     m_pPL   =new CPolyline(m_hInst);
  117.  
  118.     //Attempt to create our contained Polyline.
  119.     GetClientRect(m_hWnd, &rc);
  120.     InflateRect(&rc, -8, -8);
  121.  
  122.     if (!m_pPL->FInit(m_hWnd, &rc, WS_CHILD | WS_VISIBLE
  123.         , ID_POLYLINE, m_pPLAdv))
  124.         return FALSE;
  125.  
  126.     m_pDropTarget=new CDropTarget(this);
  127.  
  128.     if (NULL!=m_pDropTarget)
  129.         {
  130.         m_pDropTarget->AddRef();
  131.         RegisterDragDrop(m_hWnd, (LPDROPTARGET)m_pDropTarget);
  132.  
  133.         /*
  134.          * For some forsaken reason you must call CoLockObjectExternal
  135.          * on the drop target or else OLE will forget about it and lose
  136.          * the pointer after the first drag-drop in which this target
  137.          * is involved.  To prevent that loss, that is, work around
  138.          * an OLE2.DLL but, you can make sure OLE can't forget.
  139.          */
  140.         CoLockObjectExternal((LPUNKNOWN)m_pDropTarget, TRUE, FALSE);
  141.         }
  142.  
  143.  
  144.     //CHAPTER10MOD
  145.     m_pFigure=new CFigure(ObjectDestroyed, this);
  146.  
  147.     if (NULL==m_pFigure)
  148.         return FALSE;
  149.  
  150.     /*
  151.      * These two lines are 1) so we can ::Release on document closure
  152.      * and 2) if we fail FInit then we'll destroy the document which
  153.      * calls ::Release which will call ObjectDestroyed which will
  154.      * decrement g_cObj and shut down if necessary.
  155.      */
  156.     m_pFigure->AddRef();
  157.     g_cObj++;
  158.  
  159.     if (!m_pFigure->FInit())
  160.         return FALSE;
  161.     //End CHAPTER10MOD
  162.  
  163.     return TRUE;
  164.     }
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172. /*
  173.  * CSchmooDoc::FMessageHook
  174.  *
  175.  * Purpose:
  176.  *  Processes WM_SIZE for the document so we can resize the Polyline.
  177.  *
  178.  * Parameters:
  179.  *  <WndProc Parameters>
  180.  *  pLRes           LRESULT FAR * in which to store the return value
  181.  *                  for the message.
  182.  *
  183.  * Return Value:
  184.  *  BOOL            TRUE to prevent further processing, FALSE otherwise.
  185.  */
  186.  
  187. BOOL CSchmooDoc::FMessageHook(HWND hWnd, UINT iMsg, WPARAM wParam
  188.     , LPARAM lParam, LRESULT FAR *pLRes)
  189.     {
  190.     UINT        dx, dy;
  191.     RECT        rc;
  192.  
  193.     if (WM_SIZE==iMsg)
  194.         {
  195.         //Don't effect the Polyline size to or from minimized state.
  196.         if (SIZE_MINIMIZED!=wParam && SIZE_MINIMIZED !=m_uPrevSize)
  197.             {
  198.             //When we change size, resize any Polyline we hold.
  199.             dx=LOWORD(lParam);
  200.             dy=HIWORD(lParam);
  201.  
  202.             /*
  203.              * If we are getting WM_SIZE in response to a Polyline
  204.              * notification, then don't resize the Polyline window again.
  205.              */
  206.             if (!m_fNoSize && NULL!=m_pPL)
  207.                 {
  208.                 //Resize the polyline to fit the new client
  209.                 SetRect(&rc, 8, 8, dx-8, dy-8);
  210.                 m_pPL->RectSet(&rc, FALSE);
  211.  
  212.                 /*
  213.                  * We consider sizing something that makes the file dirty,
  214.                  * but not until we've finished the create process, which
  215.                  * is why we set fNoDirty to FALSE in WM_CREATE since we
  216.                  * get a WM_SIZE on the first creation.
  217.                  */
  218.                 if (!m_fNoDirty)
  219.                     FDirtySet(TRUE);
  220.  
  221.                 SetRect(&rc, 0, 0, dx, dy);
  222.  
  223.                 if (NULL!=m_pAdv)
  224.                     m_pAdv->OnSizeChange((LPCDocument)this, &rc);
  225.  
  226.                 m_fNoDirty=FALSE;
  227.                 }
  228.             }
  229.  
  230.         m_uPrevSize=wParam;
  231.         }
  232.  
  233.     if (WM_LBUTTONDOWN==iMsg)
  234.             {
  235.             LPDROPSOURCE    pIDropSource;
  236.             LPDATAOBJECT    pIDataObject;
  237.             HRESULT         hr;
  238.             SCODE           sc;
  239.             DWORD           dwEffect;
  240.  
  241.             /*
  242.              * The document has an 8 pixel border around the polyline
  243.              * window where we'll see mouse clicks.  A left mouse button
  244.              * click here means the start of a drag-drop operation.
  245.              *
  246.              * Since this is a modal operation, the IDropSource we need
  247.              * here is entirely local.
  248.              */
  249.  
  250.             pIDropSource=(LPDROPSOURCE)new CDropSource(this);
  251.  
  252.             if (NULL==pIDropSource)
  253.                 return FALSE;
  254.  
  255.             pIDropSource->AddRef();
  256.             m_fDragSource=TRUE;
  257.  
  258.             //Go get the data and start the ball rolling.
  259.             pIDataObject=TransferObjectCreate(FALSE);
  260.  
  261.             hr=DoDragDrop(pIDataObject, pIDropSource
  262.                 , DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
  263.  
  264.             pIDataObject->Release();
  265.  
  266.  
  267.             /*
  268.              * When we return from DoDragDrop, we either cancelled or dropped.
  269.              * First we can toss the IDropSource we have here, then bail out
  270.              * on cancel, and possibly clear our data on a move drop.
  271.              */
  272.  
  273.             pIDropSource->Release();
  274.  
  275.             /*
  276.              * If there was a drop on the same document (determined using
  277.              * this flag, then dwEffect will be DROPEFFECT_NONE (see
  278.              * IDropTarget_Drop in IDROPTGT.CPP).  In any case, we need
  279.              * to reset this since the operation is done.
  280.              */
  281.  
  282.             m_fDragSource=FALSE;
  283.  
  284.             sc=GetScode(hr);
  285.  
  286.             if (DRAGDROP_S_DROP==sc && DROPEFFECT_MOVE==dwEffect)
  287.                 {
  288.                 m_pPL->New();
  289.                 FDirtySet(TRUE);
  290.                 }
  291.  
  292.             //On a canceled drop or a copy we don't need to do anything else
  293.             return TRUE;
  294.             }
  295.  
  296.  
  297.     /*
  298.      * We return FALSE even on WM_SIZE so we can let the default procedure
  299.      * handle maximized MDI child windows appropriately.
  300.      */
  301.     return FALSE;
  302.     }
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311. /*
  312.  * CSchmooDoc::Clear
  313.  *
  314.  * Purpose:
  315.  *  Sets all contents in the document back to defaults with no filename.
  316.  *
  317.  * Paramters:
  318.  *  None
  319.  *
  320.  * Return Value:
  321.  *  None
  322.  */
  323.  
  324. void CSchmooDoc::Clear(void)
  325.     {
  326.     //Completely reset the polyline
  327.     m_pPL->New();
  328.  
  329.     CDocument::Clear();
  330.     m_lVer=0;
  331.     return;
  332.     }
  333.  
  334.  
  335.  
  336. //CHAPTER10MOD
  337. /*
  338.  * CSchmooDoc::FDirtySet
  339.  *
  340.  * Purpose:
  341.  *  Sets or clears the document 'dirty' flag returning the previous state
  342.  *  of that same flag.  We override this in Schmoo server to send the
  343.  *  OnDataChange notification as necessary.
  344.  *
  345.  * Parameters:
  346.  *  fDirty          BOOL indicating the new contents of the dirty flag.
  347.  *
  348.  * Return Value:
  349.  *  BOOL            Previous value of the dirty flag.
  350.  */
  351.  
  352. BOOL CSchmooDoc::FDirtySet(BOOL fDirty)
  353.     {
  354.     BOOL        fRet;
  355.  
  356.     fRet=CDocument::FDirtySet(fDirty);
  357.     m_pFigure->SendAdvise(OBJECTCODE_DATACHANGED);
  358.  
  359.     return fRet;
  360.     }
  361.  
  362.  
  363.  
  364.  
  365. /*
  366.  * CSchmooDoc::FDirtyGet
  367.  *
  368.  * Purpose:
  369.  *  Override of the normal FDirtyGet such that we never return dirty
  370.  *  for an embedded object we're serving since updates constantly happen
  371.  *  and since the object will be saved on closure.  This then prevents
  372.  *  any message boxes asking the user to save.
  373.  *
  374.  * Parameters:
  375.  *  None
  376.  *
  377.  * Return Value:
  378.  *  BOOL            TRUE if the document is dirty, FALSE otherwise.
  379.  */
  380.  
  381. BOOL CSchmooDoc::FDirtyGet(void)
  382.     {
  383.     if (m_pFigure->FIsEmbedded())
  384.         return FALSE;
  385.  
  386.     return m_fDirty;
  387.     }
  388. //End CHAPTER10MOD
  389.  
  390.  
  391.  
  392.  
  393. /*
  394.  * CSchmooDoc::ULoad
  395.  *
  396.  * Purpose:
  397.  *  Loads a given document without any user interface overwriting the
  398.  *  previous contents of the Polyline window.  We do this by opening
  399.  *  the file and telling the Polyline to load itself from that file.
  400.  *
  401.  * Parameters:
  402.  *  fChangeFile     BOOL indicating if we're to update the window title
  403.  *                  and the filename from using this file.
  404.  *  pszFile         LPSTR to the filename to load, NULL if the file is
  405.  *                  new and untitled.
  406.  *
  407.  * Return Value:
  408.  *  UINT            An error value from DOCERR_*
  409.  */
  410.  
  411. UINT CSchmooDoc::ULoad(BOOL fChangeFile, LPSTR pszFile)
  412.     {
  413.     HRESULT         hr;
  414.     LPSTORAGE       pIStorage;
  415.  
  416.     if (NULL==pszFile)
  417.         {
  418.         //For a new untitled document, just rename ourselved.
  419.         Rename(NULL);
  420.         m_lVer=VERSIONCURRENT;
  421.         return DOCERR_NONE;
  422.         }
  423.  
  424.     /*
  425.      * If this is not a Compound File, open the file using STGM_CONVERT
  426.      * in TRANSACTED mode to effectively see old files as a storage with
  427.      * one stream called "CONTENTS" (which is conveniently the name we use
  428.      * in the new files).  We must use STGM_TRANSACTED here or else
  429.      * the old file will be immediately converted on disk:  we only want
  430.      * a converted image in memory from which to read.  In addition,
  431.      * note that we need STGM_READWRITE as well since conversion is
  432.      * inherently a write operation.
  433.      */
  434.  
  435.     pIStorage=NULL;
  436.  
  437.     if (NOERROR!=StgIsStorageFile(pszFile))
  438.         {
  439.         hr=StgCreateDocfile(pszFile, STGM_TRANSACTED | STGM_READWRITE
  440.             | STGM_CONVERT | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
  441.  
  442.         if (FAILED(hr))
  443.             {
  444.             //If we were denied write access, try to load the old way
  445.             if (STG_E_ACCESSDENIED==GetScode(hr))
  446.                 m_lVer=m_pPL->ReadFromFile(pszFile);
  447.             else
  448.                 return DOCERR_COULDNOTOPEN;
  449.             }
  450.         }
  451.     else
  452.         {
  453.         hr=StgOpenStorage(pszFile, NULL, STGM_DIRECT | STGM_READ
  454.             | STGM_SHARE_EXCLUSIVE, NULL, 0, &pIStorage);
  455.  
  456.         if (FAILED(hr))
  457.             return DOCERR_COULDNOTOPEN;
  458.         }
  459.  
  460.     if (NULL!=pIStorage)
  461.         {
  462.         m_lVer=m_pPL->ReadFromStorage(pIStorage);
  463.         pIStorage->Release();
  464.         }
  465.  
  466.     if (POLYLINE_E_READFAILURE==m_lVer)
  467.         return DOCERR_READFAILURE;
  468.  
  469.     if (POLYLINE_E_UNSUPPORTEDVERSION==m_lVer)
  470.         return DOCERR_UNSUPPORTEDVERSION;
  471.  
  472.     if (fChangeFile)
  473.         Rename(pszFile);
  474.  
  475.     //Importing a file makes things dirty
  476.     FDirtySet(!fChangeFile);
  477.  
  478.     return DOCERR_NONE;
  479.     }
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487. /*
  488.  * CSchmooDoc::USave
  489.  *
  490.  * Purpose:
  491.  *  Writes the file to a known filename, requiring that the user has
  492.  *  previously used FileOpen or FileSaveAs in order to have a filename.
  493.  *
  494.  * Parameters:
  495.  *  uType           UINT indicating the type of file the user requested
  496.  *                  to save in the File Save As dialog.
  497.  *  pszFile         LPSTR under which to save.  If NULL, use the current name.
  498.  *
  499.  * Return Value:
  500.  *  UINT            An error value from DOCERR_*
  501.  */
  502.  
  503. UINT CSchmooDoc::USave(UINT uType, LPSTR pszFile)
  504.     {
  505.     LONG        lVer, lRet;
  506.     UINT        uTemp;
  507.     BOOL        fRename=TRUE;
  508.     HRESULT     hr;
  509.     LPSTORAGE   pIStorage;
  510.     //CHAPTER10MOD
  511.     BOOL        fEmbedding;
  512.  
  513.     fEmbedding=m_pFigure->FIsEmbedded();
  514.     //End CHAPTER10MOD
  515.  
  516.     if (NULL==pszFile)
  517.         {
  518.         fRename=FALSE;
  519.         pszFile=m_szFile;
  520.         }
  521.  
  522.     /*
  523.      * Type 1 is the current version, type 2 is version 1.0 of the Polyline
  524.      * so we use this to send the right version to CPolyline::WriteToFile.
  525.      */
  526.  
  527.     switch (uType)
  528.         {
  529.         case 0:         //From Save, use loaded version.
  530.             lVer=m_lVer;
  531.             break;
  532.  
  533.         case 1:
  534.             lVer=VERSIONCURRENT;
  535.             break;
  536.  
  537.         case 2:
  538.             lVer=MAKELONG(0, 1);    //1.0
  539.             break;
  540.  
  541.         default:
  542.             return DOCERR_UNSUPPORTEDVERSION;
  543.         }
  544.  
  545.     /*
  546.      * If the version the user wants to save is different than the
  547.      * version that we loaded, and m_lVer is not zero (new document),
  548.      * then inform the user of the version change and verify.
  549.      */
  550.     //CHAPTER10MOD
  551.     //For embedding, this is Save Copy As, so don't ask about versions.
  552.     if (0!=m_lVer && m_lVer!=lVer && !fEmbedding)
  553.     //End CHAPTER10MOD
  554.         {
  555.         char        szMsg[128];
  556.  
  557.         wsprintf(szMsg, PSZ(IDS_VERSIONCHANGE), (UINT)HIWORD(m_lVer)
  558.             , (UINT)LOWORD(m_lVer), (UINT)HIWORD(lVer), (UINT)LOWORD(lVer));
  559.  
  560.         uTemp=MessageBox(m_hWnd, szMsg, PSZ(IDS_DOCUMENTCAPTION), MB_YESNOCANCEL);
  561.  
  562.         if (IDCANCEL==uTemp)
  563.             return DOCERR_CANCELLED;
  564.  
  565.         //If the user won't upgrade versions, revert to loaded version.
  566.         if (IDNO==uTemp)
  567.             lVer=m_lVer;
  568.         }
  569.  
  570.     /*
  571.      * For 1.0 files, still use the old code.  For new files, use
  572.      * storages instead
  573.      */
  574.     if (lVer==MAKELONG(0, 1))
  575.         lRet=m_pPL->WriteToFile(pszFile, lVer);
  576.     else
  577.         {
  578.         hr=StgCreateDocfile(pszFile, STGM_DIRECT | STGM_READWRITE
  579.             | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, &pIStorage);
  580.  
  581.         if (FAILED(hr))
  582.             return DOCERR_COULDNOTOPEN;
  583.  
  584.         //Mark this as one of our class
  585.         WriteClassStg(pIStorage, CLSID_Schmoo2Figure);
  586.  
  587.         //Write user-readable class information
  588.         WriteFmtUserTypeStg(pIStorage, m_cf, PSZ(IDS_CLIPBOARDFORMAT));
  589.  
  590.         lRet=m_pPL->WriteToStorage(pIStorage, lVer);
  591.         pIStorage->Release();
  592.         }
  593.  
  594.     if (POLYLINE_E_NONE!=lRet)
  595.         return DOCERR_WRITEFAILURE;
  596.  
  597.     //CHAPTER10MOD
  598.     //Saving makes us clean, but this doesn't apply to embedding.
  599.     if (!fEmbedding)
  600.         FDirtySet(FALSE);
  601.     //End CHAPTER10MOD
  602.  
  603.     //Update the known version of this document.
  604.     m_lVer=lVer;
  605.  
  606.     //CHAPTER10MOD
  607.     /*
  608.      * If we're embedding, this is Save Copy As, so no rename.
  609.      * Note that we also don't care about having been set to clean
  610.      * since we're always 'clean' as an embedded object from
  611.      * the user's perspective.
  612.      */
  613.     if (fRename && !fEmbedding)
  614.         Rename(pszFile);
  615.     //End CHAPTER10MOD
  616.  
  617.     return DOCERR_NONE;
  618.     }
  619.  
  620.  
  621.  
  622.  
  623.  
  624. /*
  625.  * CSchmooDoc::Undo
  626.  *
  627.  * Purpose:
  628.  *  Reverses a previous action.
  629.  *
  630.  * Parameters:
  631.  *  None
  632.  *
  633.  * Return Value:
  634.  *  None
  635.  */
  636.  
  637. void CSchmooDoc::Undo(void)
  638.     {
  639.     m_pPL->Undo();
  640.     return;
  641.     }
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649. /*
  650.  * CSchmooDoc::FClip
  651.  *
  652.  * Purpose:
  653.  *  Places a private format, a metafile, and a bitmap of the display
  654.  *  on the clipboard, optionally implementing Cut by deleting the
  655.  *  data in the current window after rendering.
  656.  *
  657.  * Parameters:
  658.  *  hWndFrame       HWND of the main window
  659.  *  fCut            BOOL indicating cut (TRUE) or copy (FALSE).
  660.  *
  661.  * Return Value:
  662.  *  BOOL            TRUE if successful, FALSE otherwise.
  663.  */
  664.  
  665. BOOL CSchmooDoc::FClip(HWND hWndFrame, BOOL fCut)
  666.     {
  667.     BOOL            fRet=TRUE;
  668.     LPDATAOBJECT    pIDataObject;
  669.  
  670.     pIDataObject=TransferObjectCreate(fCut);
  671.  
  672.     if (NULL==pIDataObject)
  673.         return FALSE;
  674.  
  675.     fRet=SUCCEEDED(OleSetClipboard(pIDataObject));
  676.     pIDataObject->Release();
  677.  
  678.     //Delete our current data if copying succeeded.
  679.     if (fRet && fCut)
  680.         {
  681.         m_pPL->New();
  682.         FDirtySet(TRUE);
  683.         }
  684.  
  685.     return fRet;
  686.     }
  687.  
  688.  
  689.  
  690.  
  691.  
  692. /*
  693.  * CSchmooDoc::RenderFormat
  694.  *
  695.  * Purpose:
  696.  *  Renders a specific clipboard format into global memory.  We have this
  697.  *  function split out because we'll eventually move to delayed rendering
  698.  *  and this will then be immediately callable from the frame.
  699.  *
  700.  * Parameters:
  701.  *  cf              UINT format to render.
  702.  *
  703.  * Return Value:
  704.  *  HGLOBAL         Global memory handle containing the data.
  705.  */
  706.  
  707. HGLOBAL CSchmooDoc::RenderFormat(UINT cf)
  708.     {
  709.     HGLOBAL     hMem;
  710.  
  711.     if (cf==m_cf)
  712.         {
  713.         m_pPL->DataGetMem(VERSIONCURRENT, &hMem);
  714.         return hMem;
  715.         }
  716.  
  717.     switch (cf)
  718.         {
  719.         case CF_METAFILEPICT:
  720.             return m_pPL->RenderMetafilePict();
  721.  
  722.         case CF_BITMAP:
  723.             return (HGLOBAL)m_pPL->RenderBitmap();
  724.         }
  725.  
  726.     return NULL;
  727.     }
  728.  
  729.  
  730.  
  731. //CHAPTER10MOD
  732. /*
  733.  * CSchmooDoc::FRenderMedium
  734.  *
  735.  * Purpose:
  736.  *  Like RenderFormat, this function creates a specific data format
  737.  *  based on the cf parameter.  Unlike RenderFormat, we store the
  738.  *  result in a STGMEDIUM in case it has a medium other than TYMED_HGLOBAL.
  739.  *  For conveniece we'll centralize all compound document formats here,
  740.  *  hGlobal or not.
  741.  *
  742.  * Parameters:
  743.  *  cf              UINT clipboard format of interest.
  744.  *  pSTM            LSTGMEDIUM to fill.  We only fill the union and tymed.
  745.  *
  746.  * Return Value:
  747.  *  BOOL            TRUE if we could render the format, FALSE otherwise.
  748.  */
  749.  
  750. BOOL CSchmooDoc::FRenderMedium(UINT cf, LPSTGMEDIUM pSTM)
  751.     {
  752.     if (NULL==pSTM)
  753.         return FALSE;
  754.  
  755.     if (cf==m_cfEmbedSource)
  756.         {
  757.         /*
  758.          * Embed Source data is an IStorage containing the native
  759.          * data (same as Embedded Object).  Since our data is small,
  760.          * it makes the most sense to create an IStorage in memory
  761.          * and put transfer that instead of a disk-based IStorage.
  762.          */
  763.  
  764.         pSTM->pstg=OleStdCreateStorageOnHGlobal(NULL, TRUE, STGM_DIRECT
  765.             | STGM_READWRITE | STGM_SHARE_EXCLUSIVE);
  766.  
  767.         if (NULL==pSTM->pstg)
  768.             return FALSE;
  769.  
  770.         //Now save the data to the storage.
  771.         WriteClassStg(pSTM->pstg, CLSID_Schmoo2Figure);
  772.         WriteFmtUserTypeStg(pSTM->pstg, m_cf, PSZ(IDS_CLIPBOARDFORMAT));
  773.  
  774.         if (POLYLINE_E_NONE!=m_pPL->WriteToStorage(pSTM->pstg, VERSIONCURRENT))
  775.             {
  776.             /*
  777.              * When someone releases the IStorage, STORAGE.DLL will release
  778.              * the ILockBytes which, having fDeleteOnRelease=TRUE (second
  779.              * parameter) will release the memory.  That's why we don't have
  780.              * STGM_DELETEONRELEASE on the IStorage.
  781.              */
  782.             pSTM->pstg->Release();
  783.             return FALSE;
  784.             }
  785.  
  786.         pSTM->tymed=TYMED_ISTORAGE;
  787.         return TRUE;
  788.         }
  789.  
  790.     if (cf==m_cfObjectDescriptor)
  791.         {
  792.         SIZEL   szl, szlT;
  793.         POINTL  ptl;
  794.         RECT    rc;
  795.  
  796.         m_pPL->SizeGet(&rc);
  797.         SETSIZEL(szlT, rc.right, rc.bottom);
  798.         XformSizeInPixelsToHimetric(NULL, &szlT, &szl);
  799.  
  800.         SETPOINTL(ptl, 0, 0);
  801.  
  802.         pSTM->hGlobal=OleStdGetObjectDescriptorData(CLSID_Schmoo2Figure
  803.             , DVASPECT_CONTENT, szl, ptl, OLEMISC_RECOMPOSEONRESIZE
  804.             , PSZ(IDS_OBJECTDESCRIPTION), NULL);
  805.  
  806.         pSTM->tymed=TYMED_HGLOBAL;
  807.         return (NULL!=pSTM->hGlobal);
  808.         }
  809.  
  810.     return FALSE;
  811.     }
  812.  
  813.  
  814. //End CHAPTER10MOD
  815.  
  816.  
  817.  
  818.  
  819.  
  820. /*
  821.  * CSchmooDoc::FQueryPaste
  822.  *
  823.  * Purpose:
  824.  *  Determines if we can paste data from the clipboard.
  825.  *
  826.  * Parameters:
  827.  *  None
  828.  *
  829.  * Return Value:
  830.  *  BOOL            TRUE if data is available, FALSE otherwise.
  831.  */
  832.  
  833. BOOL CSchmooDoc::FQueryPaste(void)
  834.     {
  835.     LPDATAOBJECT    pIDataObject;
  836.     BOOL            fRet;
  837.  
  838.     if (FAILED(OleGetClipboard(&pIDataObject)))
  839.         return FALSE;
  840.  
  841.     fRet=FQueryPasteFromData(pIDataObject);
  842.     pIDataObject->Release();
  843.     return fRet;
  844.     }
  845.  
  846.  
  847.  
  848.  
  849.  
  850. /*
  851.  * CSchmooDoc::FQueryPasteFromData
  852.  * (Protected)
  853.  *
  854.  * Purpose:
  855.  *  Determines if we can paste data from a data object.
  856.  *
  857.  * Parameters:
  858.  *  pIDataObject    LPDATAOBJECT from which we might want to paste.
  859.  *
  860.  * Return Value:
  861.  *  BOOL            TRUE if data is available, FALSE otherwise.
  862.  */
  863.  
  864. BOOL CSchmooDoc::FQueryPasteFromData(LPDATAOBJECT pIDataObject)
  865.     {
  866.     FORMATETC       fe;
  867.  
  868.     SETDefFormatEtc(fe, m_cf, TYMED_HGLOBAL);
  869.     return (NOERROR==pIDataObject->QueryGetData(&fe));
  870.     }
  871.  
  872.  
  873.  
  874.  
  875. /*
  876.  * CSchmooDoc::FPaste
  877.  *
  878.  * Purpose:
  879.  *  Retrieves the private data format from the clipboard and sets it
  880.  *  to the current figure in the editor window.
  881.  *
  882.  *  Note that if this function is called, then the clipboard format
  883.  *  is available because the Paste menu item is only enabled if the
  884.  *  format is present.
  885.  *
  886.  * Parameters:
  887.  *  hWndFrame       HWND of the main window
  888.  *
  889.  * Return Value:
  890.  *  BOOL            TRUE if successful, FALSE otherwise.
  891.  */
  892.  
  893. BOOL CSchmooDoc::FPaste(HWND hWndFrame)
  894.     {
  895.     LPDATAOBJECT    pIDataObject;
  896.     BOOL            fRet;
  897.  
  898.     if (FAILED(OleGetClipboard(&pIDataObject)))
  899.         return FALSE;
  900.  
  901.     fRet=FPasteFromData(pIDataObject);
  902.     pIDataObject->Release();
  903.     return fRet;
  904.     }
  905.  
  906.  
  907.  
  908.  
  909.  
  910. /*
  911.  * CSchmooDoc::FPasteFromData
  912.  * (Protected)
  913.  *
  914.  * Purpose:
  915.  *  Retrieves the private data format from a data object and sets it
  916.  *  to the current figure in the editor window.
  917.  *
  918.  * Parameters:
  919.  *  pIDataObject    LPDATAOBJECT from which to paste.
  920.  *
  921.  * Return Value:
  922.  *  BOOL            TRUE if successful, FALSE otherwise.
  923.  */
  924.  
  925. BOOL CSchmooDoc::FPasteFromData(LPDATAOBJECT pIDataObject)
  926.     {
  927.     FORMATETC       fe;
  928.     STGMEDIUM       stm;
  929.     BOOL            fRet;
  930.  
  931.     SETDefFormatEtc(fe, m_cf, TYMED_HGLOBAL);
  932.     fRet=SUCCEEDED(pIDataObject->GetData(&fe, &stm));
  933.  
  934.     if (fRet && NULL!=stm.hGlobal)
  935.         {
  936.         m_pPL->DataSetMem(stm.hGlobal, FALSE, FALSE, TRUE);
  937.         ReleaseStgMedium(&stm);
  938.         FDirtySet(TRUE);
  939.         }
  940.  
  941.     return fRet;
  942.     }
  943.  
  944.  
  945.  
  946.  
  947. /*
  948.  * CSchmooDoc::TransferObjectCreate
  949.  * (Protected)
  950.  *
  951.  * Purpose:
  952.  *  Creates a DataTransferObject and stuffs the current Polyline
  953.  *  data into it, used for both clipboard and drag-drop operations.
  954.  *
  955.  * Parameters:
  956.  *  fCut            BOOL TRUE if we're cutting, FALSE for copying.
  957.  *
  958.  * Return Value:
  959.  *  LPDATAOBJECT    Pointer to the object created, NULL on failure
  960.  */
  961.  
  962. LPDATAOBJECT CSchmooDoc::TransferObjectCreate(BOOL fCut)
  963.     {
  964.     UINT            i;
  965.     HRESULT         hr;
  966.     STGMEDIUM       stm;
  967.     FORMATETC       fe;
  968.     LPDATAOBJECT    pIDataObject=NULL;
  969.     //CHAPTER10MOD
  970.     const UINT      cFormats=5;
  971.     static UINT     rgcf[5]={0, 0, 0, CF_METAFILEPICT, CF_BITMAP};
  972.     static DWORD    rgtm[5]={TYMED_HGLOBAL, TYMED_ISTORAGE, TYMED_HGLOBAL
  973.         , TYMED_MFPICT, TYMED_GDI};
  974.     //CHAPTER10MOD
  975.  
  976.     hr=CoCreateInstance(CLSID_DataTransferObject, NULL, CLSCTX_INPROC_SERVER
  977.         , IID_IDataObject, (LPVOID FAR *)&pIDataObject);
  978.  
  979.     if (FAILED(hr))
  980.         return NULL;
  981.  
  982.     rgcf[0]=m_cf;
  983.     //CHAPTER10MOD
  984.     rgcf[1]=m_cfEmbedSource;
  985.     rgcf[2]=m_cfObjectDescriptor;
  986.     //End CHAPTER10MOD
  987.  
  988.     for (i=0; i < cFormats; i++)
  989.         {
  990.         //CHAPTER10MOD
  991.         /*
  992.          * RenderFormat handles memory handles, but for compound doc
  993.          * formats we need something more.  So if RenderFormat fails
  994.          * (which it will for i=1, try our latest addition which
  995.          * writes to a different field in the STGMEDIUM.
  996.          */
  997.         stm.hGlobal=RenderFormat(rgcf[i]);
  998.  
  999.         if (NULL==stm.hGlobal)
  1000.             {
  1001.             if (!FRenderMedium(rgcf[i], &stm))
  1002.                 continue;
  1003.             }
  1004.  
  1005.         stm.tymed=rgtm[i];
  1006.         stm.pUnkForRelease=NULL;
  1007.         SETDefFormatEtc(fe, rgcf[i], rgtm[i]);
  1008.         pIDataObject->SetData(&fe, &stm, TRUE);
  1009.         //End CHAPTER10MOD
  1010.         }
  1011.  
  1012.     return pIDataObject;    //Caller now responsible
  1013.     }
  1014.  
  1015.  
  1016.  
  1017. /*
  1018.  * CSchmooDoc::DropSelectTargetWindow
  1019.  * (Protected)
  1020.  *
  1021.  * Purpose:
  1022.  *  Creates a thin inverted frame around a window that we use to show
  1023.  *  the window as a drop target.  This is a toggle function:  it uses
  1024.  *  XOR to create the effect so it must be called twice to leave the
  1025.  *  window as it was.
  1026.  *
  1027.  * Parameters:
  1028.  *  None
  1029.  *
  1030.  * Return Value:
  1031.  *  None
  1032.  */
  1033.  
  1034. void CSchmooDoc::DropSelectTargetWindow(void)
  1035.     {
  1036.     HDC         hDC;
  1037.     RECT        rc;
  1038.     UINT        dd=3;
  1039.     HWND        hWnd;
  1040.  
  1041.     hWnd=m_pPL->Window();
  1042.     hDC=GetWindowDC(hWnd);
  1043.     GetClientRect(hWnd, &rc);
  1044.  
  1045.     //Frame this window with inverted pixels
  1046.  
  1047.     //Top
  1048.     PatBlt(hDC, rc.left, rc.top, rc.right-rc.left, dd, DSTINVERT);
  1049.  
  1050.     //Bottom
  1051.     PatBlt(hDC, rc.left, rc.bottom-dd, rc.right-rc.left, dd, DSTINVERT);
  1052.  
  1053.     //Left excluding regions already affected by top and bottom
  1054.     PatBlt(hDC, rc.left, rc.top+dd, dd, rc.bottom-rc.top-(2*dd), DSTINVERT);
  1055.  
  1056.     //Right excluding regions already affected by top and bottom
  1057.     PatBlt(hDC, rc.right-dd, rc.top+dd, dd, rc.bottom-rc.top-(2*dd), DSTINVERT);
  1058.  
  1059.     ReleaseDC(hWnd, hDC);
  1060.     return;
  1061.     }
  1062.  
  1063.  
  1064.  
  1065.  
  1066.  
  1067.  
  1068. /*
  1069.  * CSchmooDoc::ColorSet
  1070.  *
  1071.  * Purpose:
  1072.  *  Changes a color used in our contained Polyline.
  1073.  *
  1074.  * Parameters:
  1075.  *  iColor          UINT index of the color to change.
  1076.  *  cr              COLORREF new color.
  1077.  *
  1078.  * Return Value:
  1079.  *  COLORREF        Previous color for the given index.
  1080.  */
  1081.  
  1082. COLORREF CSchmooDoc::ColorSet(UINT iColor, COLORREF cr)
  1083.     {
  1084.     return m_pPL->ColorSet(iColor, cr);
  1085.     }
  1086.  
  1087.  
  1088.  
  1089.  
  1090.  
  1091. /*
  1092.  * CSchmooDoc::ColorGet
  1093.  *
  1094.  * Purpose:
  1095.  *  Retrieves a color currently in use in the Polyline.
  1096.  *
  1097.  * Parameters:
  1098.  *  iColor          UINT index of the color to retrieve.
  1099.  *
  1100.  * Return Value:
  1101.  *  COLORREF        Current color for the given index.
  1102.  */
  1103.  
  1104. COLORREF CSchmooDoc::ColorGet(UINT iColor)
  1105.     {
  1106.     return m_pPL->ColorGet(iColor);
  1107.     }
  1108.  
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114. /*
  1115.  * CSchmooDoc::LineStyleSet
  1116.  *
  1117.  * Purpose:
  1118.  *  Changes the line style currently used in the Polyline
  1119.  *
  1120.  * Parameters:
  1121.  *  iStyle          UINT index of the new line style to use.
  1122.  *
  1123.  * Return Value:
  1124.  *  UINT            Previous line style.
  1125.  */
  1126.  
  1127.  
  1128. UINT CSchmooDoc::LineStyleSet(UINT iStyle)
  1129.     {
  1130.     return m_pPL->LineStyleSet(iStyle);
  1131.     }
  1132.  
  1133.  
  1134.  
  1135.  
  1136.  
  1137.  
  1138.  
  1139. /*
  1140.  * CSchmooDoc::LineStyleGet
  1141.  *
  1142.  * Purpose:
  1143.  *  Retrieves the line style currently used in the Polyline
  1144.  *
  1145.  * Parameters:
  1146.  *  None
  1147.  *
  1148.  * Return Value:
  1149.  *  UINT            Current line style.
  1150.  */
  1151.  
  1152.  
  1153. UINT CSchmooDoc::LineStyleGet(void)
  1154.     {
  1155.     return m_pPL->LineStyleGet();
  1156.     }
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162.  
  1163.  
  1164.  
  1165. /*
  1166.  * CPolylineAdviseSink::CPolylineAdviseSink
  1167.  * CPolylineAdviseSink::~CPolylineAdviseSink
  1168.  *
  1169.  * Constructor Parameters:
  1170.  *  pv              LPVOID to store in this object
  1171.  */
  1172.  
  1173. CPolylineAdviseSink::CPolylineAdviseSink(LPVOID pv)
  1174.     {
  1175.     m_pv=pv;
  1176.     return;
  1177.     }
  1178.  
  1179.  
  1180. CPolylineAdviseSink::~CPolylineAdviseSink(void)
  1181.     {
  1182.     return;
  1183.     }
  1184.  
  1185.  
  1186.  
  1187.  
  1188.  
  1189. /*
  1190.  * CPolylineAdviseSink::OnPointChange
  1191.  *
  1192.  * Purpose:
  1193.  *  Informs the document that the polyline added or removed a point.
  1194.  *
  1195.  * Parameters:
  1196.  *  None
  1197.  *
  1198.  * Return Value:
  1199.  *  None
  1200.  */
  1201.  
  1202. void CPolylineAdviseSink::OnPointChange(void)
  1203.     {
  1204.     LPCDocument pDoc=(LPCDocument)m_pv;
  1205.  
  1206.     pDoc->FDirtySet(TRUE);
  1207.     return;
  1208.     }
  1209.  
  1210.  
  1211.  
  1212.  
  1213.  
  1214.  
  1215. /*
  1216.  * CPolylineAdviseSink::OnSizeChange
  1217.  *
  1218.  * Purpose:
  1219.  *  Informs the document that the polyline changed size.
  1220.  *
  1221.  * Parameters:
  1222.  *  None
  1223.  *
  1224.  * Return Value:
  1225.  *  None
  1226.  */
  1227.  
  1228. void CPolylineAdviseSink::OnSizeChange(void)
  1229.     {
  1230.     LPCSchmooDoc pDoc=(LPCSchmooDoc)m_pv;
  1231.     RECT         rc;
  1232.     DWORD        dwStyle;
  1233.  
  1234.     /*
  1235.      * Polyline window is informing us that it changed size in
  1236.      * response to setting it's data.  Therefore we have to
  1237.      * size ourselves accordingly but without moving the screen
  1238.      * position of the polyline window.
  1239.      */
  1240.  
  1241.     pDoc->m_fNoSize=TRUE;
  1242.  
  1243.     //Set the document window size.
  1244.     GetWindowRect(pDoc->m_pPL->Window(), &rc);
  1245.     InflateRect(&rc, 8, 8);
  1246.  
  1247.     //Adjust for a window sans menu
  1248.     dwStyle=GetWindowLong(pDoc->m_hWnd, GWL_STYLE);
  1249.     AdjustWindowRect(&rc, dwStyle, FALSE);
  1250.  
  1251.     SetWindowPos(pDoc->m_hWnd, NULL, 0, 0, rc.right-rc.left
  1252.         , rc.bottom-rc.top, SWP_NOMOVE | SWP_NOZORDER);
  1253.  
  1254.     if (NULL!=pDoc->m_pAdv)
  1255.         pDoc->m_pAdv->OnSizeChange(pDoc, &rc);
  1256.  
  1257.     pDoc->m_fNoSize=FALSE;
  1258.     pDoc->FDirtySet(TRUE);
  1259.  
  1260.     return;
  1261.     }
  1262.  
  1263.  
  1264.  
  1265.  
  1266.  
  1267. /*
  1268.  * CPolylineAdviseSink::OnDataChange
  1269.  *
  1270.  * Purpose:
  1271.  *  Informs the document that the polyline data changed.
  1272.  *
  1273.  * Parameters:
  1274.  *  None
  1275.  *
  1276.  * Return Value:
  1277.  *  None
  1278.  */
  1279.  
  1280. void CPolylineAdviseSink::OnDataChange(void)
  1281.     {
  1282.     LPCSchmooDoc    pDoc=(LPCSchmooDoc)m_pv;
  1283.  
  1284.     if (NULL!=pDoc->m_pAdv)
  1285.         pDoc->m_pAdv->OnDataChange(pDoc);
  1286.  
  1287.     pDoc->FDirtySet(TRUE);
  1288.     return;
  1289.     }
  1290.  
  1291.  
  1292.  
  1293.  
  1294.  
  1295. /*
  1296.  * CPolylineAdviseSink::OnColorChange
  1297.  *
  1298.  * Purpose:
  1299.  *  Informs the document that the polyline data changed a color.
  1300.  *
  1301.  * Parameters:
  1302.  *  None
  1303.  *
  1304.  * Return Value:
  1305.  *  None
  1306.  */
  1307.  
  1308. void CPolylineAdviseSink::OnColorChange(void)
  1309.     {
  1310.     LPCSchmooDoc    pDoc=(LPCSchmooDoc)m_pv;
  1311.  
  1312.     pDoc->FDirtySet(TRUE);
  1313.     return;
  1314.     }
  1315.  
  1316.  
  1317.  
  1318.  
  1319.  
  1320. /*
  1321.  * CPolylineAdviseSink::OnLineStyleChange
  1322.  *
  1323.  * Purpose:
  1324.  *  Informs the document that the polyline changed its line style.
  1325.  *
  1326.  * Parameters:
  1327.  *  None
  1328.  *
  1329.  * Return Value:
  1330.  *  None
  1331.  */
  1332.  
  1333. void CPolylineAdviseSink::OnLineStyleChange(void)
  1334.     {
  1335.     LPCSchmooDoc    pDoc=(LPCSchmooDoc)m_pv;
  1336.  
  1337.     pDoc->FDirtySet(TRUE);
  1338.     return;
  1339.     }
  1340.